/*
 * @Author: wuqingchun
 * @Date: 2024-05-08 16:43:49
 * @Description: POSIX 版本信号量
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-05-08 17:13:34
 */
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <thread>

#define SEM_NAME "/mysem"

/**
 * @brief POSIX 版本信号量封装
 * 
 */
class IPCPosixSema
{
public:
    ~IPCPosixSema()
    {
        if (m_pstSem != nullptr)
        {
            sem_close(m_pstSem);
            m_pstSem = nullptr;
        }
    }

    int32_t Init()
    {
        m_pstSem = sem_open(SEM_NAME, O_CREAT|O_RDWR, 0666, 1);
        if (m_pstSem == nullptr)
        {
            printf("sem_open error, %s\n", strerror(errno));

            return -1;
        }

        return 0;
    }

    // 执行V操作（也称为发送信号或加号操作）的作用是释放资源或唤醒等待进程，它通过将信号量加1来实现，
    // 如果相加结果大于零，则从该信号的等待队列中唤醒一个等待进程
    int32_t Post()
    {
        if (m_pstSem == nullptr)
        {
            return -1;
        }

        // 执行P操作 +1
        return sem_post(m_pstSem);
    }

    // 执行P操作（也称为等待或减号操作）的作用是等待或请求资源，它通过将信号量减1来实现，
    // 如果信号量减1后仍大于或等于零，则进程继续执行；
    // 如果信号量减1后小于零，则该进程被阻塞并进入与该信号相对应的队列中，等待进程调度。
    int32_t Wait()
    {
        if (m_pstSem == nullptr)
        {
            return -1;
        }

        return sem_wait(m_pstSem);
    }
private:
    sem_t* m_pstSem = nullptr;
};

int main(int argc, char** argv)
{
    IPCPosixSema objSema;

    if (objSema.Init() != 0)
    {
        return 0;
    }

    if (objSema.Wait() != 0)
    {
        return 0;
    }

    while (1)
    {
        printf("do something\n");
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}